package com.project2.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

public class InformationUtil {
    /**
     * 该工具类静态方法可将po的信息转移到vo中
     * 但是必须保证两边对应的成员变量类型和名字一致
     * @param t 需要被填充的对象
     * @param info 数据源，一般为po对象
     * @param <T> 填充对象类型
     * @return 返回被填充的对象
     * @author Frank Zhu
     */
    public static <T> T infoTransfer(T t, Object info) {
        Class<?> infoObjectClass = info.getClass();
        Class<?> returnInfoObjectClass = t.getClass();

        List<Field> infoObjectFields = Arrays.asList(infoObjectClass.getDeclaredFields());
        List<Field> returnObjectFields = Arrays.asList(returnInfoObjectClass.getDeclaredFields());

        for (int i = 0; i < returnObjectFields.size(); i++) {
            Field currentField = returnObjectFields.get(i);
            Class<?> type = currentField.getType();
            String fieldName = currentField.getName();

            long count = infoObjectFields.stream().filter(a -> a.getName().equals(fieldName)).count();

            // 如果count==1，说明有对应的相同的成员变量。否则略过
            if (count != 1) {
                continue;
            }

            // 获取当前的成员变量名，对info调用get，对returnObject调用set
            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
            String setMethodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

            // 各自取到get方法和set方法
            Method getMethod = null;
            Method setMethod = null;
            try {
                getMethod = infoObjectClass.getMethod(getMethodName);
                setMethod = returnInfoObjectClass.getMethod(setMethodName, type);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }

            // 这里Objcet类型保证了成员如果为数组类型，在set的invoke时不会散开作为多参，最后出现错误
            Object setParameter = null;
            try {
                setParameter = getMethod.invoke(info);
                setMethod.invoke(t, setParameter);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return t;
    }
}
